package com.gingko.duominuo.utils

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.PixelFormat
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import java.io.ByteArrayOutputStream
import java.util.*
import kotlin.experimental.and
import kotlin.experimental.or


/**
 * Created by luyao
 * on 2019/6/14 15:43
 */

private val HEX_DIGITS =
    charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f')

/**
 * byte array to hex string
 */
fun ByteArray.toHexString(): String {
    val result = CharArray(size shl 1)
    var index = 0
    for (b in this) {
        result[index++] = HEX_DIGITS[b.toInt().shr(4) and 0xf]
        result[index++] = HEX_DIGITS[b.toInt() and 0xf]
    }
    return String(result)
}

/**
 * hex string to byte array
 */
fun String.hexToByteArray(): ByteArray {
    var len = length
    var hexString = this
    if (len % 2 != 0) {
        hexString = "0$hexString"
        len++
    }
    val hexBytes = hexString.toUpperCase(Locale.getDefault()).toCharArray()
    val ret = ByteArray(len shr 1)
    var i = 0
    while (i < len) {
        ret[i shr 1] = ((hexBytes[i].hexToInt()) shl 4 or (hexBytes[i + 1].hexToInt())).toByte()
        i += 2
    }
    return ret
}

fun Char.hexToInt(): Int {
    return when (this) {
        in '0'..'9' -> this - '0'
        in 'A'..'F' -> this - 'A' + 10
        else -> throw IllegalArgumentException()
    }
}

/**
 * byte array to int
 */
fun ByteArray.toInt(): Int = bytes2Int(this)

/**
 * int to byte array
 */
fun Int.toByteArray(): ByteArray = int2Bytes(this)

/**
 * byte array to short
 */
fun ByteArray.toShort(): Short = bytes2Short(this)

/**
 * short to byte array
 */
fun Short.toByteArray(): ByteArray = short2Bytes(this)

/**
 * byte array to long
 */
fun ByteArray.toLong(): Long = bytes2Long(this)

/**
 * long to byte array
 */
fun Long.toByteArray(): ByteArray = long2Bytes(this)

/**
 * bitmap to byte array
 */
fun Bitmap.toByteArray(format: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG): ByteArray {
    ByteArrayOutputStream().use {
        compress(format, 100, it)
        return toByteArray()
    }
}

/**
 * byte array to bitmap
 */
fun ByteArray.toBitmap(): Bitmap = BitmapFactory.decodeByteArray(this, 0, size)

/**
 * drawable to bitmap
 */
fun Drawable.toBitmap(): Bitmap {
    if (this is BitmapDrawable) return bitmap

    val bitmap = if (intrinsicHeight <= 0 || intrinsicWidth <= 0) {
        Bitmap.createBitmap(
            1,
            1,
            if (opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
        )
    } else {
        Bitmap.createBitmap(
            intrinsicWidth,
            intrinsicHeight,
            if (opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
        )
    }

    val canvas = Canvas(bitmap)
    setBounds(0, 0, canvas.width, canvas.height)
    draw(canvas)
    return bitmap
}

/**
 * bitmap to drawable
 */
fun Bitmap.toDrawable(context: Context): Drawable = BitmapDrawable(context.resources, this)

/**
 * drawable to byte array
 */
fun Drawable.toByteArray(format: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG): ByteArray =
    toBitmap().toByteArray(format)

/**
 * byte array to drawable
 */
fun ByteArray.toDrawable(context: Context): Drawable = toBitmap().toDrawable(context)


fun bytes2Int(bytes: ByteArray?): Int {
    return if (null == bytes || bytes.isEmpty()) {
        0
    } else {
        (bytes[0].toInt() and 0XFF shl 24) or (bytes[1].toInt() and 0xFF shl 16) or (bytes[2].toInt() and 0xFF shl 8) or (bytes[3].toInt() and 0xFF)
    }
}

/**
 * int 转 byte[]
 */
fun int2Bytes(i: Int): ByteArray {
    val bytes = ByteArray(4)
    bytes[0] = (i shr 24 and 0xFF).toByte()
    bytes[1] = (i shr 16 and 0xFF).toByte()
    bytes[2] = (i shr 8 and 0xFF).toByte()
    bytes[3] = (i and 0xFF).toByte()
    return bytes
}

/**
 * byte[] 转 short
 */
fun bytes2Short(bytes: ByteArray?): Short {
    return if (null == bytes || bytes.isEmpty()) {
        0
    } else {
        val result = (bytes[0].toInt() and 0xff) or ((bytes[1].toInt() and 0xff) shl 8)
        result.toShort()
    }
}

/**
 * short 转 byte[]
 */
fun short2Bytes(s: Short): ByteArray {
    var temp = s.toInt()
    val b = ByteArray(2)
    for (i in b.indices) {
        b[i] = Integer.valueOf(temp and 0xff).toByte()
        temp = temp shr 8
    }
    return b
}

/**
 * byte[] 转 long
 */
fun bytes2Long(bytes: ByteArray?): Long {
    if (null == bytes || bytes.isEmpty()) return 0
    val s0: Long = (bytes[0].toInt() and 0xff).toLong()
    var s1: Long = (bytes[1].toInt() and 0xff).toLong()
    var s2: Long = (bytes[2].toInt() and 0xff).toLong()
    var s3: Long = (bytes[3].toInt() and 0xff).toLong()
    var s4: Long = (bytes[4].toInt() and 0xff).toLong()
    var s5: Long = (bytes[5].toInt() and 0xff).toLong()
    var s6: Long = (bytes[6].toInt() and 0xff).toLong()
    var s7: Long = (bytes[7].toInt() and 0xff).toLong()
    s1 = s1 shl 8
    s2 = s2 shl 16
    s3 = s3 shl 24
    s4 = s4 shl 8 * 4
    s5 = s5 shl 8 * 5
    s6 = s6 shl 8 * 6
    s7 = s7 shl 8 * 7
    return s0 or s1 or s2 or s3 or s4 or s5 or s6 or s7
}


/**
 * long 转 byte[]
 */
fun long2Bytes(l: Long): ByteArray {
    var temp = l
    val b = ByteArray(8)
    for (i in b.indices) {
        b[i] = java.lang.Long.valueOf(temp and 0xff).toByte()
        temp = temp shr 8
    }
    return b
}